process.env.TZ = 'Asia/Shanghai';

fs = require('fs');

// mysql = require('mysql');
var uim = require('./uim.js');

var querystring = require('querystring');

var redis = require('redis');

// 环境配置（以下划线开头的配置表示允许在运行中重新赋值并立即生效）
const ENV = {
    CONSUMER_ID: fs.readFileSync('./.env/CONSUMER_ID', 'utf-8').trim(), // 消费进程编号
    REDIS: {
        PORT: fs.readFileSync('./.env/redis.port', 'utf-8').trim(),
        HOST: fs.readFileSync('./.env/redis.host', 'utf-8').trim(),
        PASSWORD: fs.readFileSync('./.env/redis.password', 'utf-8').trim(),
    },
    // MYSQL: {
    //     host: fs.readFileSync('./.env/mysql.host', 'utf-8').trim(),
    //     port: fs.readFileSync('./.env/mysql.port', 'utf-8').trim(),
    //     user: fs.readFileSync('./.env/mysql.user', 'utf-8').trim(),
    //     password: fs.readFileSync('./.env/mysql.password', 'utf-8').trim(),
    //     database: fs.readFileSync('./.env/mysql.database', 'utf-8').trim(),
    //     dateStrings: true
    // },
    _STATE: 0, // 状态：0启动中，1就绪，2活动，3暂停
    _CACHE_QUEUE_MULTIPLE: 1, // 缓存队列倍数
    _DEBUG_MODE: true,
    _QUEUE_NULL_DELAY: 500, // 空队列时延迟检查
}



var project_redis_handle = {
    // '1_1': null,
};

// var working_thread_total = 0; // 所有项目工作中的线程总数
var default_project_obj = {
    // project_id: 0, // 项目编号
    // project_name: '',
    // enable: true, // 项目启用状态
    redis_return_err: 0, // redis连接返回错误数量
    redis_return_ready: 0, // redis连接返回成功数量
    redis_return: 0, // redis连接返回总数
    redis_list: [
        // {
        //     redis_id: 0, // 队列编号
        //     ready: false,
        //     port: '', // 端口
        //     host: '', // 地址
        //     password: '', // 密码
        // }
    ],
    server_return_err: 0, // server连接返回错误数量
    server_return_ready: 0, // server连接返回成功数量
    server_return: 0, // server连接返回总数
    server_thread_ready: 0, // 所有server就绪的线程总数
    server_thread_working: 0, // 所有server工作中的线程总数
    server_list: [
        // {
        //     server_id: 0, // 服务器编号
        //     ready: false,
        //     working_thread: 0, // 当前工作线程数
        //     max_thread: 0, // 最大线程
        //     hostname: '',
        //     port: 80,
        //     path: '',
        // }
    ], // 关联当前消费进程的服务器
    queue: [] // 临时队列
};

// 关联当前消费进程的项目列表
var project_list = {};
var init_porject_list = function () {
    // 从redis/mysql中读取列表
    // 遍历并初始redis列表
    console_redis_pub.get('console_deploy|project_list|consumer_' + ENV.CONSUMER_ID, function (err, result) {
        if (err) {
            throw '读取项目列表失败';
        }
        var tmp_project_list = uim.parseJSON(result || '[]');
        if (!tmp_project_list) {
            throw '解析项目列表时数据异常';
        }
        for (var tmp_i in tmp_project_list) {
            project_list[tmp_project_list[tmp_i].project_id] = Object.assign(tmp_project_list[tmp_i], JSON.parse(JSON.stringify(default_project_obj)));
            if (!tmp_project_list[tmp_i].enable) {
                continue;
            }
            get_project_redis_list(tmp_project_list[tmp_i]);
            get_project_server_list(tmp_project_list[tmp_i]);
        }
    });
}
var get_project_redis_list = function (obj_project) {
    console_redis_pub.get('console_deploy|redis_list|consumer_' + ENV.CONSUMER_ID + '|project_' + obj_project.project_id, function (err, result) {
        if (err) {
            return console.log('读取项目redis列表失败');
        }
        var tmp_redis_list = uim.parseJSON(result);
        if (!tmp_redis_list) {
            return console.log('解析项目“' + obj_project.project_name + '”redis列表时数据异常');
        }
        obj_project.redis_list = tmp_redis_list;
        for (var tmp_i in obj_project.redis_list) {
            obj_project.redis_list[tmp_i].ready = false;
            connect_project_redis(obj_project, obj_project.redis_list[tmp_i]);
        }
    });
}
var get_project_server_list = function (obj_project) {
    console_redis_pub.get('console_deploy|api_server_list|consumer_' + ENV.CONSUMER_ID + '|project_' + obj_project.project_id, function (err, result) {
        if (err) {
            return console.log('读取项目server列表失败');
        }
        var tmp_server_list = uim.parseJSON(result);
        if (!tmp_server_list) {
            return console.log('解析项目“' + obj_project.project_name + '”server列表时数据异常');
        }
        obj_project.server_list = tmp_server_list;
        for (var tmp_i in obj_project.server_list) {
            obj_project.server_list[tmp_i].ready = false;
            obj_project.server_list[tmp_i].working_thread = 0;
            test_project_server(obj_project, obj_project.server_list[tmp_i]);
        }
        // test_project_server_list(obj_project);
    });
}
var connect_project_redis = function (obj_project, obj_redis) {

    var redis_handle = obj_project.project_id + '_' + obj_redis.redis_id;

    project_redis_handle[redis_handle] = redis.createClient(obj_redis.port, obj_redis.host, { auth_pass: obj_redis.password });
    project_redis_handle[redis_handle].on('ready', function (err) {
        if (err) {
            console.log(err);
            console.log('项目“' + obj_project.project_name + '”连接接口队列失败：' + redis_handle);
            obj_project.redis_return_err++;
        } else {
            obj_redis.ready = true;
            console.log('项目“' + obj_project.project_name + '”已连接到接口队列：' + redis_handle);
            obj_project.redis_return_ready++;
        }
        obj_project.redis_return++;
        // 当所有redis连接返回
        if (obj_project.redis_return == obj_project.redis_list.length) {
            // 如果有失败的redis连接
            if (obj_project.redis_return_err) {
                console.log('项目“' + obj_project.project_name + '”共尝试连接队列' + obj_project.redis_return +
                    '个，有' + obj_project.redis_return_err + '个连接失败，请解决后通过控制台重新发起连接！');
            }
            // test_project_server_list(obj_project);
        }
    });
}
// var test_project_server_list = function (obj_project) {

//     for (var tmp_i in obj_project.server_list) {
//         test_project_server(obj_project, obj_project.server_list[tmp_i]);
//     }
// }
var test_project_server_return = 0;// 进程初始时测试接口服务器返回数量，用于标识是否启动redis订阅端
var test_project_server = function (obj_project, obj_server) {
    http_request({
        hostname: obj_server.hostname,
        port: obj_server.port,
        path: obj_server.path,
        method: default_http_options.method,
        headers: default_http_options.headers
    }, {
        req_id: 0,
        client_id: '',
        session_id: '',
        code: 'test.env',
        args: JSON.stringify({
            consumer_id: ENV.CONSUMER_ID,
        })
    }, function (err, response, duration) {
        if (err) {
            console.log('项目“' + obj_project.project_name + '”测试接口服务器失败：' +
                obj_server.hostname + ':' + obj_server.port + obj_server.path + '\n错误信息：' + err);
            obj_project.server_return_err++;
        } else {
            var data = uim.parseJSON(response);
            if (data && data.code === 0) {
                obj_server.ready = true;
                console.log('项目“' + obj_project.project_name + '”测试接口服务器成功：' +
                    obj_server.hostname + ':' + obj_server.port + obj_server.path + '，耗时：' + duration);
                obj_project.server_return_ready++;
                obj_project.server_thread_ready += obj_server.max_thread;
            } else {
                console.log('项目“' + obj_project.project_name + '”测试接口服务器时返回异常：' +
                    obj_server.hostname + ':' + obj_server.port + obj_server.path + '，耗时：' + duration +
                    '\n错误信息：' + response);
                obj_project.server_return_err++;

            }
        }
        obj_project.server_return++;
        // 当所有server测试连接返回
        if (obj_project.server_return == obj_project.server_list.length) {
            // 如果有失败的server连接
            if (obj_project.server_return_err) {
                console.log('项目“' + obj_project.project_name + '”共测试接口服务器' + obj_project.server_return +
                    '个，有' + obj_project.server_return_err + '个连接失败，请解决后通过控制台重新发起连接！');
            }
            test_project_server_return++;
            if (test_project_server_return == Object.keys(project_list).length) {
                init_redis_subscribe();
            }
        }
    });
}
var start_project_req_queue = function () {

    for (var tmp_i in project_list) {
        // // 如果当前项目状态未启用，则跳过
        // if (!project_list[tmp_i].enable) {
        //     continue;
        // }
        project_redis_list_rpop(project_list[tmp_i]);
    }
}
var project_redis_list_rpop = function (obj_project) {
    // 如果当前项目状态未启用，则跳过
    if (!obj_project.enable) {
        return;
    }

    // 如果当前项目缓存队列数量少于设置的倍数，则继续从redis_list中取出请求
    var tmp_cache_queue_count = obj_project.server_thread_ready * ENV._CACHE_QUEUE_MULTIPLE;

    if (obj_project.queue.length < Math.max(tmp_cache_queue_count, obj_project.redis_return_ready)) {
        var this_get_count = 0, this_callback_count = 0, redis_count = 0;
        var callback = function (success) {
            this_callback_count++;
            if (success) this_get_count++;
            if (this_callback_count == redis_count) {

                if (this_get_count) {
                    // 如果本轮拿到了数据，则继续拿
                    project_redis_list_rpop(obj_project);
                } else {
                    // 否则说明所有队列已空，定时监控即可
                    setTimeout(function () {
                        project_redis_list_rpop(obj_project);
                    }, ENV._QUEUE_NULL_DELAY);
                }
                project_server_request(obj_project);
            }
        }
        for (var tmp_i in obj_project.redis_list) {
            // 如果当前redis服务器未连接成功则跳过
            if (!obj_project.redis_list[tmp_i].ready) {
                continue;
            }
            redis_count++;
            project_redis_rpop(obj_project, obj_project.redis_list[tmp_i], callback);
        }
    }
}
var project_redis_rpop = function (obj_project, obj_redis, callback) {
    var redis_handle = obj_project.project_id + '_' + obj_redis.redis_id;
    project_redis_handle[redis_handle].rpop('api_queue|project_' + obj_project.project_id, function (err, result) {
        // if (err) {
        //     // 发送控制台消息
        // }
        if (result) {
            obj_project.queue.push({
                redis_id: obj_redis.redis_id,
                params: result
            });
            console.log('project_' + obj_project.project_id + ' 从redis取出任务，当前本地任务数：' + obj_project.queue.length + ' / ' + uim.dateTime());
            // rpop_count++;
            callback(true);
        } else {
            callback(false);
        }
    });
}
var project_server_request = function (obj_project) {
    // 如果当前项目状态未启用，则跳过
    if (!obj_project.enable) {
        return;
    }
    var req_data;
    for (var tmp_i in obj_project.server_list) {
        // 如果当前接口服务器未连接成功，或当前工作线程已达最大值，则跳过
        if (!obj_project.server_list[tmp_i].ready
            || obj_project.server_list[tmp_i].working_thread > obj_project.server_list[tmp_i].max_thread) {
            continue;
        }
        req_data = obj_project.queue.shift();
        if (!req_data) {
            return;
        }
        // 向该服务器发起消费请求
        project_server_run_api(obj_project, obj_project.server_list[tmp_i], req_data.redis_id, req_data.params);
    }
    // // 如果以上循环中产生了请求，则说明请求队列和可用服务器列表都不为空，自动循环调用
    if (req_data) {
        project_redis_list_rpop(obj_project);
        project_server_request(obj_project);
    }
}
var project_server_run_api = function (obj_project, obj_server, redis_id, params) {
    // working_thread_total++;
    obj_project.server_thread_working++;
    obj_server.working_thread++;
    var send_req = uim.parseJSON(params);
    var api_time_ms = new Date().getTime();
    http_request({
        hostname: obj_server.hostname,
        port: obj_server.port,
        path: obj_server.path,
        method: default_http_options.method,
        headers: default_http_options.headers
    }, send_req, function (err, response, duration) {
        // working_thread_total--;
        obj_project.server_thread_working--;
        obj_server.working_thread--;
        // 继续判断当前项目是否有待执行请求
        project_server_request(obj_project);
        project_redis_list_rpop(obj_project);
        var data;
        if (err) {
            data = {
                code: 19,
                msg: '接口请求失败：' + err
            };
        } else {
            data = uim.parseJSON(response);
            if (!data || typeof data.code != 'number') {
                data = {
                    code: 19,
                    msg: '接口返回异常：' + response
                }
            }
        }
        var redis_handle = obj_project.project_id + '_' + redis_id;
        project_redis_handle[redis_handle].publish('api_producer|socket_server_' + send_req.socket_server_id + '|project_' + obj_project.project_id, JSON.stringify({
            req_id: send_req.req_id,
            socket_id: send_req.socket_id,
            data,
            duration,
            server_id: obj_server.server_id,
            api_time_ms,
            return_ms: new Date().getTime(),
        }));
    });
}
var deploy_project = function (project_id) {
    // 挂载项目
    if (project_list[project_id]) {
        // 发送控制消息
    } else {
        project_list[project_id] = {
            redis: {},
            enable: true,
        }
        // 发送控制消息
    }
}
var pause_project = function (project_id) {
    // 暂停项目（不断开redis）
}
var restart_project = function (project_id) {
    // 暂停项目（不断开redis）
}
var delete_project = function (project_id) {
    // 卸载项目（遍历断开redis）
}

var http_request = function (http_options, params, callback, timeout,) {

    var http = require('http');
    var response = "";

    var http_start_time = new Date().getTime();
    var req = http.request(http_options, function (res) {
        var status = res.statusCode;
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            response += chunk;
        });
        res.on('end', function () {
            var duration = new Date().getTime() - http_start_time;
            callback(null, response, duration);
        });
    });
    req.on('error', function (e) {
        var duration = new Date().getTime() - http_start_time;
        callback(e.message, null, duration);
    });
    timeout && req.setTimeout(timeout, function () {
        callback('请求超时');
    })
    params && req.write(querystring.stringify(params));
    req.end();
}

var default_http_options = {
    // hostname: '127.0.0.9',
    // port: 80,
    // path: '/api/router',
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    }
}

//创建数据库连接池
// conn_pool = mysql.createPool(ENV.MYSQL);


// 用于连接控制台，接收控制信息
var console_redis_sub = undefined;

// 用于连接控制台，向控制台发出广播事件
var console_redis_pub = redis.createClient(ENV.REDIS.PORT, ENV.REDIS.HOST, { auth_pass: ENV.REDIS.PASSWORD });
console_redis_pub.on('ready', function (err) {
    // 如果连接控制台失败
    if (err) {
        console.log(err);
        throw 'pub连接控制台失败'
    } else {

        console.log('pub已连接到控制台');
        init_porject_list(); // 初始项目列表

    }
});

var init_redis_subscribe = function () {
    console_redis_sub = redis.createClient(ENV.REDIS.PORT, ENV.REDIS.HOST, { auth_pass: ENV.REDIS.PASSWORD });
    console_redis_sub.on('ready', function (err) {
        // 如果连接控制台失败
        if (err) {
            throw 'sub连接本地控制台失败'
        } else {
            console.log('sub已连接到本地控制台');
        }
    });
    console_redis_sub.subscribe('consumer_' + ENV.CONSUMER_ID); // 按consumer编号订阅广播事件
    console_redis_sub.on('subscribe', function (channel, count) {
        console.log(`got subscribe event: ${channel} and count is ${count}`);
    });
    console_redis_sub.on('connect', function () {
        //订阅客户端接收到消息
        console_redis_sub.on('message', function (channel, message) {
            var time = new Date().getTime();
            var response = `${time} received message from ${channel}:${message}`;
            // console.log(response);
            switch (channel) {
                case 'debug':
                    run_debug(message);
                default:
                    break;
            }
        });
        ENV._STATE = 1; // 消费进程已就绪
        console.log('消费进程已就绪');
        start_project_req_queue();
    });
}
var run_debug = function (debug_code) {
    console.log('debug: ' + debug_code);
    //此调试方法只在调试模式下使用
    if (ENV._DEBUG_MODE) eval(debug_code);
}


console.log('api consumer is running: ' + uim.dateTime() + ', consumer_id: ' + ENV.CONSUMER_ID);

// todo 将各项目的事件直接在api消费者中间件中进行处理（跨项目调用公共接口时处理来源项目事件会比较麻烦）
